package trigger

import (
	"bgs/db"
	sqlc "bgs/db/sqlc"
	nsqModel "bgs/nsqp/model"
	nsqpUtil "bgs/nsqp/util"
	activityService "bgs/service/activity"
	"bgs/util"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/nsqio/go-nsq"
	"go.uber.org/zap"
	"strconv"
)

var (
	lastSendCheckIn1RemindNotificationMessage *nsqModel.CronMomentMessage = nil
)

// SendCheckIn1RemindNotificationHanlder 发送签到1提醒通知 handler
type SendCheckIn1RemindNotificationHanlder struct {
	dao             *db.PgDao
	slog            *zap.SugaredLogger
	topic           string
	failover        *nsqpUtil.NsqFailover
	activityService *activityService.ActivityServiceImp
}

// NewSendCheckIn1RemindNotificationHanlder create a new handler for SendCheckIn1RemindNotification
func NewSendCheckIn1RemindNotificationHanlder(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	topic string,
	failover *nsqpUtil.NsqFailover,
	activityService *activityService.ActivityServiceImp,
) *SendCheckIn1RemindNotificationHanlder {
	return &SendCheckIn1RemindNotificationHanlder{
		dao:             pgdao,
		slog:            slog.With("module", "SendCheckIn1RemindNotificationHanlder"),
		topic:           topic,
		failover:        failover,
		activityService: activityService,
	}
}

// HandleMessage implements the Handler interface.
func (h *SendCheckIn1RemindNotificationHanlder) HandleMessage(m *nsq.Message) error {
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}

	h.slog.Infof("SendCheckIn1RemindNotificationMessage=>%s", string(m.Body))

	v := &nsqModel.CronMomentMessage{}
	if decodeErr := json.NewDecoder(bytes.NewReader(m.Body)).Decode(v); decodeErr != nil {
		return fmt.Errorf("无法解析信息[SendCheckIn1RemindNotificationMessage]: %v", decodeErr)
	}
	if lastSendCheckIn1RemindNotificationMessage != nil && lastSendCheckIn1RemindNotificationMessage.TS >= v.TS {
		h.slog.Infof("过时的消息: lastSendCheckIn1RemindNotificationMessage.TS:%v,v.TS:%v", lastSendCheckIn1RemindNotificationMessage.TS, v.TS)
		return nil
	}

	ts := v.TS
	limit := util.Int32IfThenElse(v.Data.Limit > 0, v.Data.Limit, 100)
	reqID := strconv.FormatInt(ts, 10)
	ctx := context.WithValue(context.Background(), util.RequestID{}, reqID)
	activityNotificationType := sqlc.EmActivityNotificationTypeRemind

	var err error
	defer h.failover.BackupSubMsgWhenHandleFail(ctx, &err, nsqpUtil.BackupSubMsgParam{
		Ts:    ts,
		Topic: h.topic,
		Mbody: m.Body,
	})

	err = h.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		activityIDs, err := q.ListCheckIn1ActivityIDsBeforeTheMoment(ctx, util.MsToGoTime(ts))
		if err != nil {
			return
		}
		activityCount := len(activityIDs)

		for _, activityID := range activityIDs {
			total, err2 := q.CountActivityUserNotificationByActivityID(ctx, sqlc.CountActivityUserNotificationByActivityIDParams{
				ActivityID: activityID,
				Type:       string(activityNotificationType),
			})
			if err2 != nil {
				err = err2
				return
			}
			if total > 0 {
				// 可以改造成iterator
				round_count := util.CeilToInt64(float64(total) / float64(limit))
				round_remain := int32(total) % limit
				for round := 0; round < int(round_count); round++ {
					roundOffset := int32(round) * limit
					roundLimit := limit
					if int64(roundOffset+roundLimit) > total {
						roundLimit = round_remain
					}
					go func(offset, limit int32) {
						h.activityService.AsyncSendUserNotificationByActivityID(ctx, activityService.AsyncSendUserNotificationByActivityIDParam{
							ActivityID: activityID,
							Type:       activityNotificationType,
							Offset:     offset,
							Limit:      limit,
						})
					}(roundOffset, roundLimit)
				}

			}
		}

		h.slog.Infof("a CheckIn1RemindHanlder-签到1提醒品牌数(%d),提醒数(%d) ok", activityCount, 0)
		return
	})

	if err != nil {
		return err
	}
	lastSendCheckIn1RemindNotificationMessage = v
	// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
	return nil
}
